Skip to content

Convert warnings to exceptions in standard lib (reopened) #5004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from

Conversation

kocsismate
Copy link
Member

Reopening #4937 after it has been rebased to current master.

@kocsismate kocsismate changed the title Standard exceptions (reopened) Converting warnings to exceptions in the standard lib (reopened) Dec 11, 2019
@kocsismate kocsismate changed the title Converting warnings to exceptions in the standard lib (reopened) Convert warnings to exceptions in standard lib (reopened) Dec 11, 2019
@@ -83,7 +83,7 @@ static zend_string* php_password_make_salt(size_t length) /* {{{ */
zend_string *ret, *buffer;

if (length > (INT_MAX / 3)) {
php_error_docref(NULL, E_WARNING, "Length is too large to safely generate");
zend_value_error("Length is too large to safely generate");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit can be dropped, password_* changes have landed separately.

@@ -1050,7 +1050,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in

if (resource->path == NULL) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "Invalid path provided in %s", url);
zend_value_error("Invalid path provided in %s", url);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general rule of thumb, I don't think we should be throwing from inside stream wrapper operations. Beyond "filename cannot contain null bytes" I think we should stick with existing warnings where file-system operations are concerned.

@@ -219,7 +219,7 @@ php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *pa

if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) {
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "URL file-access is disabled in the server configuration");
zend_throw_error(NULL, "URL file-access is disabled in the server configuration");
Copy link
Member

@nikic nikic Dec 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. This seems like a clear "environment configuration" case that code may need to deal with.

php_error_docref(NULL, E_WARNING, "Filename cannot be empty!");
RETURN_FALSE;
zend_value_error("Filename cannot be empty!");
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cmb69 What do you think about moving this check into Z_PARAM_PATH? It seems to be a pretty common check (and it's also checked in php_stream_open_wrapper), but we probably don't check it everywhere we should be checking it. That would make sure it's treated consistently.

(Conversely: Are there any cases where an empty path should be accepted?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are at least some cases where an empty path should be accepted, e.g. for SQLite3::open() (where an empty path is supposed to create a temporary on-disk database). Generally, I think that empty paths should be forbidden right away nonetheless. Maybe change Z_PARAM_PATH to reject empty paths, and cater to the few exceptions by checking for a string and adding a manual NUL byte check? Or maybe introduce another macro (say, Z_PARAM_PATH_MAYBE_EMPTY)? The latter won't work with classic ZPP, though (don't think that would a problem though).

php_error_docref(NULL, E_WARNING, "browscap ini directive not set");
RETURN_FALSE;
zend_throw_error(NULL, "Browscap ini directive not set");
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho this is again an environment issue: Code may have to deal with the fact that browscap is not available.

php_error_docref(NULL, E_WARNING, "Dynamically loaded extensions aren't enabled");
RETURN_FALSE;
zend_throw_error(NULL, "Dynamically loaded extensions aren't enabled");
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar here, environment issue.

php_error_docref(NULL, E_WARNING, "Host cannot be empty");
RETURN_FALSE;
zend_value_error("Host cannot be empty");
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine :)

@@ -354,7 +354,7 @@ static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */
option = PHP_STREAM_META_GROUP_NAME;
value = Z_STRVAL_P(group);
} else {
php_error_docref(NULL, E_WARNING, "parameter 2 should be string or int, %s given", zend_zval_type_name(group));
zend_type_error("Parameter 2 should be string or int, %s given", zend_zval_type_name(group));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, but RETURN_FALSE should be changed to return.

@@ -123,7 +123,7 @@ PHP_FUNCTION(levenshtein)
}

if (distance < 0 && /* TODO */ ZEND_NUM_ARGS() != 3) {
php_error_docref(NULL, E_WARNING, "Argument string(s) too long");
zend_value_error("Argument string(s) too long");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code may want to handle this condition, as I don't think the limit is exposed (and it's a low limit -- this is not a 2G string condition).

goto exit_fail;
}
if (Z_TYPE_P(ztarget) != IS_LONG) {
php_error_docref(NULL, E_WARNING, "Redirection target must be an integer");
zend_value_error("Redirection target must be an integer");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should all be fine.

php_error_docref(NULL, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
zend_value_error("Offset not contained in string");
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are a bit borderline (I wouldn't be surprised if there is code ignoring this warning out there), but overall I think we should do this change.

php_error_docref(NULL, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
zend_value_error("Offset not contained in string");
return;
}
p = ZSTR_VAL(haystack) + (size_t)offset;
e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
} else {
if (offset < -INT_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These INT_MAX should be ZEND_LONG_MAX.

@kocsismate
Copy link
Member Author

Thanks for the thorough review! Let me sum it up:

  • Warnings OK to promote:
  • Warnings probably OK to promote:
    • "Offset not contained in string": 761842d
  • Warnings might be OK to promote:
    • register_shutdown_function() 30f05c1
  • No decision yet:
    • register_tick_function(): c90cce3
    • constant(): f38e877
    • ini_get_all(): e6b3915 (although it also seems a configuration issue for me)

Conclusion: I shouldn't create such a big PR with many promotions next time.. :)

Can I go ahead and commit the promotions in the first category (after addressing the comment about RETURN_FALSE)?

@nikic
Copy link
Member

nikic commented Dec 20, 2019

Can I go ahead and commit the promotions in the first category (after addressing the comment about RETURN_FALSE)?

Yeah. I'd also suggest to handle Command array element %d contains a null byte for proc_open as well.

kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
kocsismate added a commit to kocsismate/php-src that referenced this pull request Dec 20, 2019
@kocsismate
Copy link
Member Author

@nikic Ah, I made a mistake and also committed the "Offset not contained in string" one as well :/ :/ Should I revert it?

@nikic
Copy link
Member

nikic commented Dec 20, 2019

@kocsismate It's okay.

@nikic
Copy link
Member

nikic commented Jan 3, 2020

* Warnings might be OK to promote:
  
  * `register_shutdown_function()` [30f05c1](https://github.com/php/php-src/commit/30f05c137201474bfcd5efec8e819453f6472e8f)

* No decision yet:
  
  * `register_tick_function()`: [c90cce3](https://github.com/php/php-src/commit/c90cce347cacaa33838acb9638f33407a91f082d)

For these two, I think we shouldn't do the conversion, as the exception will only get thrown on the actual call, not when the function is registered. That means it's doing to be e.g. thrown when handling shutdown functions, which is not the best place to throw exceptions (in particular, it's going to skip all remaining shutdown functions).

  * `constant()`: [f38e877](https://github.com/php/php-src/commit/f38e8779c04e04772209c6e11ca0c4289dd1aeaa)

I'm uncertain on that one... Generally, I think it would make sense to make constant() behaviorally consistent with a plain constant access. For that we should pass through the existing engine errors through, by removing the quiet flag, not changing the custom error.

  * `ini_get_all()`: [e6b3915](https://github.com/php/php-src/commit/e6b39156a1e7134c1431742c6d4b269a5af04a48) (although it also seems a configuration issue for me)

Yeah.

I think everything that should land here has landed (apart from constant maybe, which needs a different implementation), so I'll close this PR now.

@nikic nikic closed this Jan 3, 2020
@kocsismate kocsismate deleted the standard-exceptions branch January 3, 2020 15:00
@kocsismate
Copy link
Member Author

I think everything that should land here has landed

Cool, thanks for having a look! I also think that we are ok after learning about the facts you wrote.

I'll maybe try to have a look at the constant stuff at a later time if I can do something about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants